package aino;

import java.io.*;
import java.util.*;

public class CodeLines {
    Vector lines;
    Vector labels;
    boolean useBanks;

    public CodeLines() {
	lines = new Vector();
	labels = new Vector();
	useBanks = true;
    }

    void addCode(String line) {
	lines.add(new Code("", line));
    }

    void addCodeComment(String line, String comment) {
	lines.add(new Code("", line, comment));
    }

    void addLabel(String lbl) {
	lines.add(new Code(lbl, ""));
    }

    void addImportantLabel(String lbl) {
	labels.add(lbl);
    }

    void addComment(String comment) {
	lines.add(new Code("", "", comment));
    }

    void checkBanks() {
	int bank = 0;
	String prevAcc = null;

	useBanks = false;

	Code prevCode = null;
	for (int i = 0; i < lines.size(); i++) {
	    Code cd = (Code)lines.elementAt(i);
	    String currentCode = cd.getCode();
	    if (currentCode.length() > 0 &&
		currentCode.charAt(0) != '*' &&
		currentCode.charAt(0) != 'M') {
		if ((currentCode.startsWith("movwf") ||
		     currentCode.startsWith("clrf") ||
		     currentCode.indexOf(",") > 0)) {
		    int x = currentCode.indexOf('\t');
		    int y = currentCode.indexOf(',');
		    String var;
		    if (y > 0) var = currentCode.substring(x+1, y);
		    else var = currentCode.substring(x+1);
		    int addr = Aino.getVarAddress(var);
		    if (addr > 0) {
			int newBank = addr & ~(Aino.bankSize-1);
			cd.bank = newBank;
			if (bank != newBank) {
			    useBanks = true;
			}
		    }

		    if (currentCode.startsWith("movwf")) {
			if (var.equals("_ACC"))
			    cd.acc = prevCode.acc;
			else 
			    cd.acc = var;
		    } else if (currentCode.startsWith("movf") &&
			       prevCode != null &&
			       prevCode.acc != null &&
			       prevCode.acc.equals(var)) {
			cd.ignore = true;
			cd.acc = var;
		    }
		}
	    } // if
	    prevCode = cd;
	} // for
    }

    void print(PrintWriter out) {
	int bank = 0;
	String prevAcc = null;
	boolean btf = false;

	checkBanks();

	out.println(Aino.crlf);
	for (int i = 0; i < lines.size(); i++) {
	    Code cd = (Code)lines.elementAt(i);
	    String currentLabel = cd.getLabel();
	    String currentCode = cd.getCode();
	    String currentComment = cd.getComment();

	    if (currentLabel != null && 
		currentLabel.length() > 0) {
		for (int j = 0; j < labels.size(); j++) {
		    if (currentLabel.equals((String)labels.elementAt(j))) {
			out.println(currentLabel+Aino.crlf);
			if (i > 0) bank = -1; // execution might jump here
			break;
		    }
		}
	    }

	    int len;
	    if ((len = currentCode.length()) > 0) {
		if (currentCode.charAt(0) == '*') {
		    out.print(currentCode.substring(1));
		    //bank = -1; // we have no idea what is happening
		} else { 
		    if (useBanks && cd.bank >= 0) {
			if (cd.bank != bank) {
			    out.println("bseladdr\tset\t"+cd.bank+Aino.crlf);
			    out.println("\tbanksel\tbseladdr"+Aino.crlf);
			    bank = cd.bank;
			}
		    } else if (currentCode.startsWith("call") ||
			       currentCode.startsWith("goto")) {
			int x = currentCode.indexOf('\t');
			String var = currentCode.substring(x+1);
			if (var.indexOf('$') < 0 && btf == false) {  // not a local jump
			    out.println("\tIF ($ >> 10) != ("+var+" >> 10)"+Aino.crlf);
			    out.println("\tpagesel\t"+var+Aino.crlf);
			    out.println("\tENDIF"+Aino.crlf);
			}

			if (currentCode.startsWith("call") && bank != 0) {
			    out.println("\tbanksel\t_ACC"+Aino.crlf);
			    bank = 0;
			}
		    } else if (currentCode.startsWith("return")) {
			if (bank != 0) {
			    out.println("\tbanksel\t_ACC"+Aino.crlf);
			    bank = -1;
			}
		    }
		    if (!cd.ignore) 
			out.print("\t"+currentCode);
		}
		if (currentComment != null && 
		    currentComment.length() > 0) {
		    for (int k = 0; k < 40-len; k++) out.print(' ');
		    out.print(" ; "+currentComment);
		}
		out.println(Aino.crlf);

		if (currentCode.startsWith("btf") ||
		    currentCode.startsWith("decfsz") ||
		    currentCode.startsWith("incfsz")) btf = true;
		else btf = false;
	    } else if (currentComment != null && 
		       currentComment.length() > 0) {
		    out.println(";---- "+currentComment+Aino.crlf);
	    }

	}
    }

    public void clear() {
	lines.clear();
	labels.clear();
    }
}
